﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Medianamik.Core;
using Medianamik.Core.DAL;
using Medianamik.Core.Sugar;
using Medianamik.UI.Web.MVP.View;
using Telerik.Web.UI;

namespace Medianamik.UI.Web.MVP.Presentation
{
    public abstract class ModulePresenterWithGridBase<TItem, TView> :
        ModulePresenter<TView>
        where TItem : class
        where TView : IModuleViewWithGrid
    {
        protected ModulePresenterWithGridBase(TView view)
            : base(view)
        {
            View.Grid.GridCreating += GridCreating;
        }

        protected override void Initialize(object sender, EventArgs e)
        {
            base.Initialize(sender, e);

            View.Grid.GridDataBound += GridDataBound;
            View.Grid.PageIndexChanged += GridPageIndexChanged;
            View.Grid.PageSizeChanged += GridPageSizeChanged;
            View.CultureChanged += CultureChanged;

            if (!View.IsPostBack)
            {
                View.PageIndex = PageIndex;
                View.PageSize = PageSize;

                View.ReturnUrl = IsRoot ?
                    View.ListingPageUrl : GetReturnUrlFromQueryString().UrlDecodeBase64();

                Bind();

                if (View.AddButton != null)
                {
                    View.AddButton.NavigateUrl = AddUrl;
                }
            }
        }

        protected override void BindBreadcrumbTrail()
        {
            var nodeId = View.QueryString.GetValue<Guid?>(DefaultParamNames.NodeID);
            if (nodeId != null)
            {
                BreadcrumbBuilder.AppendNode(View.RawUrl, DefaultParamNames.NodeID, nodeId.Value, true);
            }
            else
            {
                base.BindBreadcrumbTrail();
            }
            View.BreadcrumbTrail = BreadcrumbBuilder.ToString();
        }

        protected virtual void GridCreating(object sender, GridItemEventArgs e)
        {
            if (e.Item.ItemType == GridItemType.Item ||
                e.Item.ItemType == GridItemType.AlternatingItem)
            {
                var element = (GridDataItem)e.Item;

                SetCustomGridColumnsAtCreation(element);
            }
        }

        protected virtual void CultureChanged(object sender, CultureChangedEventArgs e)
        {
            Bind();
        }

        protected virtual void GridPageSizeChanged(object sender, GridPageSizeChangedEventArgs e)
        {
            PageSizeChanged(sender, new NumericalEventArgs(e.NewPageSize));
        }

        protected virtual void GridPageIndexChanged(object sender, GridPageChangedEventArgs e)
        {
            PageIndexChanged(sender, new NumericalEventArgs(e.NewPageIndex + 1));
        }

        protected virtual void GridDataBound(object sender, GridItemEventArgs e)
        {
            if (e.Item.ItemType == GridItemType.Item ||
                e.Item.ItemType == GridItemType.AlternatingItem)
            {
                var element = (GridDataItem)e.Item;

                if (element.DataItem != null)
                {
                    var item = element.DataItem as TItem;

                    if (item != null)
                    {
                        SetGridRowCSS(element, item);
                        SetCustomGridColumns(element, item);
                    }
                }
            }
        }

        protected virtual void SetGridRowCSS(GridDataItem item, TItem element) { }

        protected virtual void SetCustomGridColumns(GridItem item, TItem nodeType)
        {
            SetNameColumn(item.FindControl("NameGridItem") as Literal, nodeType);
        }

        protected virtual void SetCustomGridColumnsAtCreation(GridItem item)
        {
        }

        protected abstract void SetNameColumn(ITextControl nameGridItem, TItem nodeTypeProp);

        protected virtual string ChildrenListingPageUrl
        {
            get { return View.ChildrenListingPageUrl; }
        }

        protected virtual string ChildrenListingPageParamName
        {
            get { return DefaultParamNames.ParentNodeTypeID; }
        }

        protected virtual string GetReturnUrlFromQueryString()
        {
            return View.QueryString.GetValue<string>(DefaultParamNames.ReturnURL);
        }

        protected virtual string BuildReturnUrl()
        {
            var returlUrl = View.ListingPageUrl;

            if (View.AllowPaging)
            {
                if (PageIndex != 1)
                    returlUrl = returlUrl.AddParam("pageindex", PageIndex);

                if (PageSize != DefaultPageSize)
                    returlUrl = returlUrl.AddParam("pagesize", PageSize);
            }

            if (ParentNodeId != ModuleNodeId)
            {
                returlUrl = returlUrl
                    .AddParam(DefaultParamNames.ParentNodeID, ParentNodeId)
                    .AddParam(DefaultParamNames.ReturnURL, GetReturnUrlFromQueryString());
            }

            return returlUrl;
        }

        protected abstract PagedCollection<TItem> GetData();

        protected virtual void Rebind(object sender, EventArgs e)
        {
            View.PageIndex = 1;
            Bind();
        }

        protected virtual void Bind()
        {
            View.EditReturnUrl = "&returnurl=" + BuildReturnUrl().UrlEncodeBase64();

            ValidateArguments();

            var pagedCollection = GetData();

            View.TotalCount = pagedCollection.TotalCount;
            View.DataSource = pagedCollection.Collection.Cast<object>();

            View.Grid.UpdateGrid();
        }

        protected virtual void ValidateArguments()
        {
            if (PageSize < 1)
                throw new Exception("Page size must be higher than 0.");
        }

        protected virtual void PageIndexChanged(object sender, NumericalEventArgs e)
        {
            if (e.Number.HasValue && e.Number.Value != PageIndex)
            {
                PageIndex = e.Number.Value;
                Bind();
            }
        }

        protected virtual void PageSizeChanged(object sender, NumericalEventArgs e)
        {
            if (e.Number.HasValue && e.Number.Value != PageSize)
            {
                PageSize = e.Number.Value;
                Bind();
            }
        }

        protected virtual Guid? ParentNodeId
        {
            get { return View.ParentNodeId; }
        }

        protected virtual Guid ModuleNodeId
        {
            get { return View.ModuleNodeId; }
        }

        protected virtual string AddUrl
        {
            get
            {
                return String.IsNullOrEmpty(View.TypeSelectorUrl) ? View.EditPageUrl
                        .AddParam(DefaultParamNames.ParentNodeID, ParentNodeId)
                        .AddParam(DefaultParamNames.ReturnURL, EditReturnUrl.UrlEncodeBase64())
                        .AddParam(DefaultParamNames.HideTreeview, true) :
                    View.TypeSelectorUrl.AddParam(DefaultParamNames.ParentNodeID, ParentNodeId);
            }
        }

        protected virtual IEnumerable<string> GetReturnUrls()
        {
            var returnUrl = GetReturnUrlFromQueryString();

            while (!String.IsNullOrEmpty(returnUrl))
            {
                returnUrl = returnUrl.DecodeBase64();
                yield return returnUrl;
                returnUrl = GetReturnUrlFromString(returnUrl);
            }
        }

        protected virtual String GetReturnUrlFromString(string url)
        {
            var uri = new Uri("http://www.google.com" + url);
            return HttpUtility.ParseQueryString(uri.Query).GetValue<string>(DefaultParamNames.ReturnURL);
        }

        protected virtual CultureInfo CurrentEditionCulture
        {
            get
            {
                return View.CurrentEditionCulture;
            }
        }

        protected virtual CultureInfo CurrentUICulture
        {
            get
            {
                return View.CurrentUICulture;
            }
        }

        private bool? _isRoot;
        protected virtual bool IsRoot
        {
            get { return _isRoot ?? (_isRoot = GetIsRoot()).GetValueOrDefault(true); }
        }

        protected virtual bool GetIsRoot()
        {
            return String.IsNullOrEmpty(GetReturnUrlFromQueryString());
        }

        private int? _pageIndex;
        protected virtual int PageIndex
        {
            get
            {
                return _pageIndex ?? (_pageIndex = GetPageIndex()).GetValueOrDefault(1);
            }
            set { _pageIndex = value; }
        }
        protected virtual int? GetPageIndex()
        {
            return View.IsPostBack ? View.PageIndex : View.QueryString.GetValue<int?>("pageindex");
        }

        private int? _pageSize;
        protected virtual int PageSize
        {
            get
            {
                return _pageSize ?? (_pageSize = GetPageSize()).GetValueOrDefault(DefaultPageSize);
            }
            set { _pageSize = value; }
        }
        protected virtual int? GetPageSize()
        {
            return View.IsPostBack ? View.PageSize : View.QueryString.GetValue<int?>("pagesize");
        }
        protected virtual int DefaultPageSize
        {
            get
            {
                return 10;
            }
        }

        private string _editReturnUrl;
        protected string EditReturnUrl
        {
            get
            {
                return _editReturnUrl ?? (_editReturnUrl = BuildReturnUrl());
            }
        }
    }
}